package cn.qidd.keep.common.controller.dict;

import cn.qidd.keep.common.model.DataDict;
import cn.qidd.keep.domain.core.Result;
import cn.qidd.keep.domain.core.dict.Dict;
import cn.qidd.keep.domain.core.dict.DictItem;
import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.SystemPropertyUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Created by sunyanping on 2018/9/17
 */
@RestController
@RequestMapping("/api/dict")
@Api(description = "字典管理", value = "DictController")
public class DictController {

    private final Logger logger = LoggerFactory.getLogger(DictController.class);

    private final static String JOINER = ".";
    private final static String BASE_PACKAGE = "cn.qidd.keep.domain.core.dict";
    private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    @GetMapping("/getAllDict")
    @ApiOperation(value = "获取所有数据字典", notes = "获取所有数据字典")
    public Result<List<DataDict>> getAllDict() {
        List<DataDict> dataDictList = Lists.newArrayList();
        for (Class clazz : findDictAnnotationClass()) {
            Field[] fields = clazz.getFields();
            String simpleName = clazz.getSimpleName();
            for (Field field : fields) {
                String code = simpleName
                        .concat(JOINER)
                        .concat(field.getName());
                Object[] objects = dictItemNameAndSeq(field);
                if (objects != null) {
                    dataDictList.add(new DataDict(code, (String) objects[0], (int) objects[1]));
                }
            }
        }
        return new Result<>(Result.Status.SUCCESS, dataDictList);
    }

    private Set<Class> findDictAnnotationClass() {
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
        Set<Class> clazzSet = new HashSet<>();
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                ClassUtils.convertClassNameToResourcePath(SystemPropertyUtils.resolvePlaceholders(BASE_PACKAGE)) + "/" + DEFAULT_RESOURCE_PATTERN;
        try {
            Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
            for (Resource resource : resources) {
                //检查resource，这里的resource都是class
                Class clazz = loadClass(metadataReaderFactory, resource);
                if (clazz != null) {
                    clazzSet.add(clazz);
                }
            }
        } catch (Exception ex) {
            logger.error("加载数据字典类出现错误", ex);
        }
        return clazzSet;
    }

    private static Class loadClass(MetadataReaderFactory metadataReaderFactory, Resource resource) throws IOException, ClassNotFoundException {
        if (resource.isReadable()) {
            MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
            Class aClass = Class.forName(metadataReader.getClassMetadata().getClassName());
            if (aClass.getAnnotation(Dict.class) != null) {
                return aClass;
            }
        }
        return null;
    }

    private static Object[] dictItemNameAndSeq(Field field) {
        DictItem annotation = field.getAnnotation(DictItem.class);
        if (annotation == null) {
            return null;
        }
        return new Object[]{annotation.name(), annotation.seq()};
    }
}
